package com.htgd.gardenexpo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.htgd.gardenexpo.dao.*;
import com.htgd.gardenexpo.entity.*;
import com.htgd.gardenexpo.page.LeisureSportsQuery;
import com.htgd.gardenexpo.service.*;
import com.htgd.gardenexpo.utils.GaoDeUtils;
import com.htgd.gardenexpo.utils.HttpRequest;
import com.htgd.gardenexpo.utils.TokenUtil;
import com.htgd.gardenexpo.utils.UUIDUtils;
import com.htgd.gardenexpo.vo.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sun.security.util.Cache;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.util.*;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static com.htgd.gardenexpo.utils.CalculationUtils.*;

/**
 * <p>
 * 休闲运动 服务实现类
 * </p>
 *
 * @author author
 * @since 2024-09-27
 */
@Service
public class GeConLeisureSportsServiceImpl extends ServiceImpl<GeConLeisureSportsMapper, GeConLeisureSports> implements IGeConLeisureSportsService {

    @Autowired
    private GeConLeisureSportsMapper geConLeisureSportsMapper;

    @Autowired
    private GeBaseDictService geBaseDictService;

    @Autowired
    private GeConUserCompeteMapper geConUserCompeteMapper;

    @Autowired
    private GeConLeisurePrizeMapper geConLeisurePrizeMapper;

    @Autowired
    private WxUserService wxUserService;

    @Autowired
    private DeviceService deviceService;

    @Autowired
    private GeConLineMapper geConLineMapper;

    @Value("${device.tenant_id}")
    private String tenantId;

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    private static final String DELAYED_MESSAGES_ZSET = "delayed:messages";

    @Autowired
    private DelayMessageMapper delayMessageMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private WxUserCollectService wxUserCollectService;

    @Autowired
    private GeConSocialTopicsMapper geConSocialTopicsMapper;

    @Autowired
    private GaoDeUtils gaoDeUtils;

    @Autowired
    private WxUserDao wxUserDao;

    @Autowired
    private GeConChallengeSportsTaskMapper geConChallengeSportsTaskMapper;

    @Autowired
    private IGeConWeatherService geConWeatherService;

    @Value("${local.url}")
    public String local_url;

    @Override
    public PageInfo<GeConLeisureSportsVO> pageList(LeisureSportsQuery leisureSportsQuery) {
        PageHelper.startPage(leisureSportsQuery.getPageNum(), leisureSportsQuery.getPageSize());
        List<GeConLeisureSportsVO> list= geConLeisureSportsMapper.pageList(leisureSportsQuery);
        for (GeConLeisureSportsVO geConLeisureSportsVO : list) {
            //获取字典值
            if(geConLeisureSportsVO.getStatus()!=null){
                geConLeisureSportsVO.setStatusText(geBaseDictService.getStatusText(String.valueOf(geConLeisureSportsVO.getStatus())));
            }

            if(geConLeisureSportsVO.getIsTop()!=null){
                geConLeisureSportsVO.setIsTopText(geBaseDictService.getTopText(String.valueOf(geConLeisureSportsVO.getIsTop())));
            }

            if(geConLeisureSportsVO.getType()!=null){
                geConLeisureSportsVO.setTypeText(geBaseDictService.getTextByCodeAndValue("type_leisure",geConLeisureSportsVO.getType()));
            }

            //已报名人数
            Long num = geConUserCompeteMapper.selectCount(
                    new LambdaQueryWrapper<GeConUserCompete>()
                            .eq(GeConUserCompete::getMotionId, geConLeisureSportsVO.getId())
                            .eq(GeConUserCompete::getSportsType,"2")
                            .eq(GeConUserCompete::getStatus, "1"));
            geConLeisureSportsVO.setNum(num);
        }
        return new PageInfo<>(list);
    }

    @Override
    public GeConLeisureSportsVO getDetailsById(String id, HttpServletRequest request) {
        GeConLeisureSportsVO geConLeisureSportsVO = new GeConLeisureSportsVO();
        GeConLeisureSports geConLeisureSports = geConLeisureSportsMapper.selectById(id);
        BeanUtils.copyProperties(geConLeisureSports,geConLeisureSportsVO);
        //获取openId
        String accessToken = request.getHeader("Access_token");
        String openId = TokenUtil.getUsernameFromToken(accessToken);
        //当前时间
        LocalDateTime now = LocalDateTime.now();
        geConLeisureSportsVO.setNow(now);
        //赛事时间
        geConLeisureSportsVO.setStart(geConLeisureSportsVO.getStartTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        geConLeisureSportsVO.setEnd(geConLeisureSportsVO.getEndTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
        //获取字典值
        if(geConLeisureSportsVO.getStatus()!=null){
            geConLeisureSportsVO.setStatusText(geBaseDictService.getStatusText(String.valueOf(geConLeisureSportsVO.getStatus())));
        }
        if(geConLeisureSportsVO.getIsTop()!=null){
            geConLeisureSportsVO.setIsTopText(geBaseDictService.getTopText(String.valueOf(geConLeisureSportsVO.getIsTop())));
        }
        if(geConLeisureSportsVO.getType()!=null){
            geConLeisureSportsVO.setTypeText(geBaseDictService.getTextByCodeAndValue("type_leisure",geConLeisureSportsVO.getType()));
        }
        if(geConLeisureSportsVO.getActive()!=null){
            geConLeisureSportsVO.setActiveText(geBaseDictService.getTextByCodeAndValue("status_competition",geConLeisureSportsVO.getActive()));
        }
        //报名状态
        if(Objects.nonNull(openId)&& !openId.equals("")){
            GeConUserCompete geConUserCompete = geConUserCompeteMapper.selectOne(new LambdaQueryWrapper<GeConUserCompete>()
                    .eq(GeConUserCompete::getStatus, "1")
                    .eq(GeConUserCompete::getOpenId, openId)
                    .eq(GeConUserCompete::getMotionId, id)
                    .eq(GeConUserCompete::getSportsType, "2"));
            //报名id
            if(geConUserCompete!=null){
                geConLeisureSportsVO.setEnrollId(geConUserCompete.getId());
            }
            //报名状态
            if(geConUserCompete!=null&&"1".equals(geConUserCompete.getStatus())){
                geConLeisureSportsVO.setSignUp("1");
                geConLeisureSportsVO.setSignUpText("已报名");
            }else{
                geConLeisureSportsVO.setSignUp("0");
                geConLeisureSportsVO.setSignUpText("未报名");
            }
        }
        //热门
        if(Objects.equals(geConLeisureSportsVO.getHot(),"0")) geConLeisureSportsVO.setHotText("普通");
        if(Objects.equals(geConLeisureSportsVO.getHot(),"1")) geConLeisureSportsVO.setHotText("热门");
        //规则
        String result = "";
        if(geConLeisureSportsVO.getRule()!=null){
            String text = geBaseDictService.getTextByCodeAndValue(
                    "rule_leisure",geConLeisureSportsVO.getRule());
            //匹配括号
            String patternString = "\\(.*?\\)|\\（.*?\\)|\\(.*?\\）|\\（.*?\\）";
            Pattern pattern = Pattern.compile(patternString);
            Matcher matcher = pattern.matcher(text);
            //获得单位
            while (matcher.find()) {
                String matchedString = matcher.group(0);
                // 移除括号
                result = matchedString.substring(1, matchedString.length() - 1);
            }
            //获取类型
            String output = text.replaceAll(patternString, "");
            //拼接
            StringBuffer groupName = new StringBuffer();
            geConLeisureSportsVO.setGroupName(groupName.append(output).append(" ").append(geConLeisureSportsVO.getTarget()).append(result).toString());
        }
        //报名人头像
        List<String> openIds = geConUserCompeteMapper.selectList(new LambdaQueryWrapper<GeConUserCompete>()
                .eq(GeConUserCompete::getSportsType, "2")
                .eq(GeConUserCompete::getMotionId,id)
                .eq(GeConUserCompete::getStatus,"1")
                .orderByDesc(GeConUserCompete::getCreateTime)
                .last("limit 5")).stream().map(x->x.getOpenId()).collect(Collectors.toList());
        if(!openIds.isEmpty()){
            List<String> imageUrls = openIds.stream()
                    .map(item -> {
                        // 查找 WxUser 对象
                        WxUser user = wxUserService.getOne(new LambdaQueryWrapper<WxUser>().eq(WxUser::getOpenId, item));
                        // 如果找到了用户，则使用用户的 URL；如果找不到，则使用默认 URL
                        return Optional.ofNullable(user)
                                .map(u -> Optional.ofNullable(u.getUrl()).orElse(local_url + "head/moren.jpeg"))
                                .orElse(local_url + "head/moren.jpeg");
                    })
                    .collect(Collectors.toList());

            geConLeisureSportsVO.setImages(imageUrls);
        }else{
            geConLeisureSportsVO.setImages(new ArrayList<>());
        }
        //已报名人数
        geConLeisureSportsVO.setNum(geConUserCompeteMapper.selectCount(
                new LambdaQueryWrapper<GeConUserCompete>()
                        .eq(GeConUserCompete::getSportsType, "2")
                        .eq(GeConUserCompete::getMotionId,id)
                        .eq(GeConUserCompete::getStatus,"1")));

        //天气
        JSONObject weather = geConWeatherService.getWeather();
        if(weather!=null){
            geConLeisureSportsVO.setWeather(weather);
        }

        //浏览量加1
        lambdaUpdate().eq(GeConLeisureSports::getId,id)
                .setSql("hit = hit + 1")
                .update();

        //进度
        String deckId = wxUserDao.getDeckId(openId);
        if(deckId!=null){
            Map<String,Object> completeDate = geConLeisureSportsMapper.getCompleteData(deckId,geConLeisureSportsVO.getId());
            Map<String,Object> completeDate2 = geConChallengeSportsTaskMapper.getCompleteData(openId,geConLeisureSportsVO.getId());
            if("1".equals(geConLeisureSportsVO.getRule())){ //时长
                //完成
                BigDecimal duration = (BigDecimal) completeDate.get("duration");
                BigDecimal duration2 = (BigDecimal) completeDate2.get("duration");
                BigDecimal duration3 = duration.add(duration2);
                String percentage = getPercentage(String.valueOf(duration3), geConLeisureSportsVO.getTarget());
                geConLeisureSportsVO.setComplete(percentage);
                //剩余
                String subtraction = getSubtraction2(String.valueOf(duration3), geConLeisureSportsVO.getTarget());
                geConLeisureSportsVO.setRemain(subtraction);
            }else{
                //完成
                Double mileage = (Double) completeDate.get("mileage");
                Double mileage2 = (Double) completeDate2.get("mileage");
                Double mileage3 = mileage+ mileage2;
                String percentage = getPercentage2(String.valueOf(mileage3), geConLeisureSportsVO.getTarget());
                geConLeisureSportsVO.setComplete(percentage);
                //剩余
                String subtraction = getSubtraction(String.valueOf(mileage), geConLeisureSportsVO.getTarget());
                geConLeisureSportsVO.setRemain(subtraction+"公里");
            }
        }else {
            geConLeisureSportsVO.setComplete("0");
            if("1".equals(geConLeisureSportsVO.getRule())) { //时长
                geConLeisureSportsVO.setRemain("00:00");
            }else {
                geConLeisureSportsVO.setRemain("0"+"公里");
            }
        }

        return geConLeisureSportsVO;
    }

    @Transactional
    @Override
    public CommonResult insert(GeConLeisureSports geConLeisureSports) {
        if(geConLeisureSports.getEndDate().isAfter(geConLeisureSports.getEndTime())){
            return CommonResult.error("报名结束时间不能在活动结束时间之后");
        }
        //话题名字不能重复
        boolean exists = geConSocialTopicsMapper.exists(new LambdaQueryWrapper<GeConSocialTopics>().eq(GeConSocialTopics::getName, geConLeisureSports.getName()));
        if(exists){
            return CommonResult.error("该名字已被话题占用，请重新命名");
        }
        geConLeisureSports.setActive("0");
        geConLeisureSports.setStatus(4);
        save(geConLeisureSports);
        return CommonResult.success("添加成功");
    }

    @Transactional
    @Override
    public CommonResult edit(GeConLeisureSports geConLeisureSports) {
        if(geConLeisureSports.getEndDate().isAfter(geConLeisureSports.getEndTime())){
            return CommonResult.error("报名结束时间不能在活动结束时间之后");
        }
        geConLeisureSports.setActive("0");
        geConLeisureSports.setStatus(4);
        updateById(geConLeisureSports);
        return CommonResult.success("修改成功");
    }

    @Transactional
    @Override
    public CommonResult delete(String id) {
        GeConLeisureSports geConLeisureSports = new GeConLeisureSports();
        geConLeisureSports.setId(id);
        geConLeisureSports.setIsDelete(1);
        updateById(geConLeisureSports);
        return CommonResult.success("删除成功");
    }

    @Transactional
    @Override
    public CommonResult review(GeConLeisureSports geConLeisureSports) {
        GeConLeisureSports geConLeisureSports2 = geConLeisureSportsMapper.selectById(geConLeisureSports.getId());

        //发布
        if(Objects.equals(geConLeisureSports.getStatus(),3)){
//            System.out.println(LocalDateTime.now().isBefore(geConLeisureSports2.getStartTime()));
            if(LocalDateTime.now().isBefore(geConLeisureSports2.getStartTime())){
                updateById(geConLeisureSports);
                DelayMessage delayMessage = new DelayMessage();
                delayMessage.setId(UUIDUtils.generateUniqueString());
                delayMessage.setType("2");
                delayMessage.setContent(JSON.toJSONString(geConLeisureSports2));
                delayMessage.setExpireTime(geConLeisureSports2.getStartTime().toEpochSecond(ZoneOffset.of("+8")) * 1000);
                delayMessage.setStatus("1");
                redisTemplate.opsForZSet().add(DELAYED_MESSAGES_ZSET, JSON.toJSONString(delayMessage),
                        geConLeisureSports2.getStartTime().toEpochSecond(ZoneOffset.of("+8")) * 1000);
                delayMessageMapper.insert(delayMessage);
                DelayMessage delayMessage2 = new DelayMessage();
                delayMessage2.setId(UUIDUtils.generateUniqueString());
                delayMessage2.setType("2");
                delayMessage2.setContent(JSON.toJSONString(geConLeisureSports2));
                delayMessage2.setExpireTime(geConLeisureSports2.getEndTime().toEpochSecond(ZoneOffset.of("+8")) * 1000);
                delayMessage2.setStatus("2");
                redisTemplate.opsForZSet().add(DELAYED_MESSAGES_ZSET, JSON.toJSONString(delayMessage2),
                        geConLeisureSports2.getEndTime().toEpochSecond(ZoneOffset.of("+8")) * 1000);
                delayMessageMapper.insert(delayMessage2);

                //插入赛事话题
                GeConSocialTopics geConSocialTopics = new GeConSocialTopics();
                geConSocialTopics.setName(geConLeisureSports2.getName());
                geConSocialTopics.setType("1");
                geConSocialTopics.setStatus("1");
                geConSocialTopicsMapper.insert(geConSocialTopics);
            }else{
                return CommonResult.error("当前时间晚于活动开始时间，不允许发布");
            }
        }else{
            updateById(geConLeisureSports);
        }
        return CommonResult.success("成功");
    }

    @Override
    public CommonResult<List<LeisureSportsNumsVO>> getEntryNums(Integer pageNum, Integer pageSize, String startTime, String endTime, String startDate, String endDate, String type, String orderBy) {

        PageHelper.startPage(pageNum,pageSize);
        List<LeisureSportsNumsVO> competitionSportsNumsVOS = geConLeisureSportsMapper.getEntryNums(startTime,endTime,startDate,endDate,type,orderBy);

        return CommonResult.success("查询成功",competitionSportsNumsVOS);
    }

    public static <T> Consumer<T> getIndex(BiConsumer<T, Integer> consumer) {
        class IndexObject {
            int index;
        }
        IndexObject indexObject = new IndexObject();
        return i -> {
            consumer.accept(i, indexObject.index++);
        };
    }
}
